package plgbase

import (
	"dgo/goutils/utils"
	"fmt"
	"gitee.com/ymofen/gobase"
	"gitee.com/ymofen/gobase/subpub"
	"gitee.com/ymofen/supervalue"
	"io"
	"sync/atomic"
)

type PlgBasePub struct {
	statuscode       int32
	pubSessionPrefix string
	pubsessionid     string
	pubconf          string
	pubTemplate      string
	pub              subpub.PubSessionIntf
	pubTopic         string
	stepMsg          string
}

var (
	pubsessionN int32
)

// subprefix 创建session时的前缀
func NewPlgBasePub(subprefix string) *PlgBasePub {
	rval := &PlgBasePub{pubSessionPrefix: subprefix, statuscode: STATUS_INIT}
	return rval
}

func (this *PlgBasePub) ConfString() string {
	return this.pubconf
}

func (this *PlgBasePub) Valid() bool {
	return this.pub != nil
}

func (this *PlgBasePub) GetTopic() string {
	return this.pubTopic
}

func (this *PlgBasePub) GetPubSessionID() string {
	return this.pubsessionid
}

func (this *PlgBasePub) closePub() {
	if len(this.pubsessionid) > 0 {
		this.pub = nil
		this.stepMsg = fmt.Sprintf("[%s]closePub->DelSession:0", utils.NowString())
		subpub.DefaultPub.DelSession(this.pubsessionid)
		this.stepMsg = fmt.Sprintf("[%s]closePub->DelSession:1", utils.NowString())
		this.pubsessionid = ""
		this.pubconf = ""
		this.statuscode = STATUS_CLOSED
	}
}

func (this *PlgBasePub) Pub(topic string, max int, args ...interface{}) int {
	pub := this.pub
	if pub == nil {
		return -1
	}
	if len(topic) == 0 {
		topic = this.pubTopic
	}

	return pub.Pub(topic, max, args...)
}

func (this *PlgBasePub) CreateTemplateJSON(cache bool) *wrapper.SuperValue {
	if len(this.pubTemplate) == 0 {
		return wrapper.NewSVObjectCache(cache)
	}
	json, _ := wrapper.NewSVFromBufCache([]byte(this.pubTemplate), cache)
	if json == nil {
		return wrapper.NewSVObjectCache(cache)
	} else {
		return json
	}
}

func (this *PlgBasePub) Close() error {
	if len(this.pubsessionid) == 0 {
		return io.ErrClosedPipe
	}
	this.closePub()
	return nil
}

func (this *PlgBasePub) GetStepMsg() string {
	return this.stepMsg
}

// 0: 未初始化
// 1: 正常
// -1: 已经关闭
// -3: 加载出错
func (this *PlgBasePub) StatusCode() int32 {
	return this.statuscode
}

func (this *PlgBasePub) StatusText() string {
	return fmt.Sprintf("valid:%v(%d), %s, step:%s", this.Valid(), this.statuscode, this.ConfString(), this.stepMsg)
}

func (this *PlgBasePub) ReloadConnConfString(str string, notify subpub.SubFunc) error {
	if str != this.pubconf {
		confMap := gobase.NewStrMap()
		this.closePub()
		this.pubconf = str
		confMap.URLFormDecode(str)

		if len(this.pubsessionid) == 0 {
			this.pubsessionid = fmt.Sprintf("%s-%d", this.pubSessionPrefix, atomic.AddInt32(&pubsessionN, 1))
		}

		this.pubTopic = confMap["topic"]

		this.pubTemplate = confMap["templ"]

		this.stepMsg = fmt.Sprintf("[%s]checkSub->AddSession:0", utils.NowString())
		if notify == nil {
			notify = func(id, topic string, args ...interface{}) (ok bool) {
				return true
			}
		}
		pub, err := subpub.DefaultPub.AddSession(this.pubsessionid, confMap, notify)
		if err != nil {
			this.stepMsg = fmt.Sprintf("[%s]checkPub->AddSession:-1, err:%s", utils.NowString(), err.Error())
			gobase.LogPrintf("%s", this.stepMsg)
			this.statuscode = STATUS_FAIL
			return err
		} else {
			this.stepMsg = fmt.Sprintf("[%s]checkPub->AddSession:1", utils.NowString())
			this.statuscode = STATUS_OK
			this.pub = pub
		}
	}
	return nil
}

func (this *PlgBasePub) ReloadConf(conf *wrapper.SuperValue, notify subpub.SubFunc) error {
	if conf == nil {
		this.closePub()
		return nil
	}

	str := conf.String()
	if str != this.pubconf {
		confMap := gobase.NewStrMap()
		this.closePub()
		this.pubconf = str
		if conf.IsString() {
			confMap.URLFormDecode(str)
		} else if conf.IsObject() {
			url := conf.StringByName("url", "")
			if len(url) > 0 {
				confMap.URLFormDecode(url)
			}
			conf.Range(func(key string, val *wrapper.SuperValue) bool {
				confMap[key] = val.String()
				return true
			})
		}

		if len(this.pubsessionid) == 0 {
			this.pubsessionid = fmt.Sprintf("%s-%d", this.pubSessionPrefix, atomic.AddInt32(&pubsessionN, 1))
		}

		this.pubTopic = confMap["topic"]
		this.pubTemplate = confMap["templ"]

		this.stepMsg = fmt.Sprintf("[%s]checkSub->AddSession:0", utils.NowString())
		if notify == nil {
			notify = func(id, topic string, args ...interface{}) (ok bool) {
				return true
			}
		}
		pub, err := subpub.DefaultPub.AddSession(this.pubsessionid, confMap, notify)
		if err != nil {
			this.stepMsg = fmt.Sprintf("[%s]checkPub->AddSession:-1, err:%s", utils.NowString(), err.Error())
			this.statuscode = -2
			return err
		} else {
			this.stepMsg = fmt.Sprintf("[%s]checkPub->AddSession:1", utils.NowString())
			this.pub = pub
			this.statuscode = 1
		}
	}
	return this.ReloadConnConfString(str, notify)
}
